import React, { ReactNode, useEffect, useMemo } from 'react';
import ReactDOM, { createPortal, unmountComponentAtNode } from 'react-dom';
import styles from './Message.less';
import { shakeIt, isEmpty } from '@/utils/common';
import Spinning from '../Spinning/Spinning';

export type IMessage = {
  content: string | ReactNode;
  showIcon?: boolean;
  icon?: ReactNode;
  duration?: number;
  onClose?: Function;
};

let msgWrap: HTMLDivElement;

/* 初始化外部容器 */
const initWrap = () => {
  if (!msgWrap) {
    msgWrap = document.createElement('div');
    document.body.appendChild(msgWrap);
  }
  msgWrap.className = styles.message_wrap;
  const msgBox = document.createElement('div');
  msgWrap.appendChild(msgBox);
  return msgBox;
};

interface IContent extends IMessage {
  type: 'success' | 'info' | 'error' | 'warn' | 'loading';
  rootNode: HTMLDivElement;
  parentNode: Element | DocumentFragment;
}

/* 消息组件 */
const Content: React.FC<IContent> = props => {
  // 默认关闭时间 3 秒
  const { rootNode, parentNode, showIcon = true, duration = 2 } = props;

  // 卸载
  const unmount = useMemo(() => {
    return () => {
      if (parentNode && rootNode) {
        if (props.type === 'loading' && isEmpty(props.duration)) {
          return false;
        }
        unmountComponentAtNode(parentNode);
        rootNode.removeChild(parentNode);
      }
    };
  }, [parentNode, rootNode]);

  useEffect(() => {
    setTimeout(() => {
      unmount();
      props.onClose && props.onClose();
    }, duration * 1000);
  }, []);

  return (
    <div className={styles[`box_${props.type}`]}>
      {showIcon && (props.icon ? props.icon : <i className={styles.icon}></i>)}
      <span>{props.content}</span>
    </div>
  );
};

/* 类型 - 信息 */
const info = (params: IMessage | string | string) => {
  let parentNode = initWrap();
  parentNode.className = styles.message_box;
  if (typeof params === 'string') {
    params = {
      content: params,
      showIcon: true,
    };
  }
  ReactDOM.render(
    <Content
      rootNode={msgWrap}
      parentNode={parentNode}
      type="info"
      {...params}
    />,
    parentNode,
  );
};

/* 类型 - 成功 */
const success = (params: IMessage | string) => {
  let parentNode = initWrap();
  parentNode.className = styles.message_box;
  if (typeof params === 'string') {
    params = {
      content: params,
      showIcon: true,
    };
  }
  ReactDOM.render(
    <Content
      rootNode={msgWrap}
      parentNode={parentNode}
      type="success"
      {...params}
    />,
    parentNode,
  );
};

/* 类型 - 警告 */
const warn = (params: IMessage | string) => {
  let parentNode = initWrap();
  parentNode.className = styles.message_box;
  if (typeof params === 'string') {
    params = {
      content: params,
      showIcon: true,
    };
  }
  ReactDOM.render(
    <Content
      rootNode={msgWrap}
      parentNode={parentNode}
      type="warn"
      {...params}
    />,
    parentNode,
  );
};

/* 类型 - 错误 */
const error = (params: IMessage | string) => {
  shakeIt(500);
  let parentNode = initWrap();
  parentNode.className = styles.message_box;
  if (typeof params === 'string') {
    params = {
      content: params,
      showIcon: true,
    };
  }
  ReactDOM.render(
    <Content
      rootNode={msgWrap}
      parentNode={parentNode}
      type="error"
      {...params}
    />,
    parentNode,
  );
};

/* 类型 - loading */
const loading = (params: IMessage | string): { hide: Function } => {
  let parentNode = initWrap();
  parentNode.className = styles.message_box;
  if (typeof params === 'string') {
    params = {
      content: params,
      showIcon: true,
    };
  }
  params['icon'] = (
    <Spinning className={styles.icon_loading} type="circle" size={28} />
  );
  ReactDOM.render(
    <Content
      rootNode={msgWrap}
      parentNode={parentNode}
      type="loading"
      {...params}
    />,
    parentNode,
  );
  return {
    hide: () => {
      if (parentNode && msgWrap) {
        unmountComponentAtNode(parentNode);
        msgWrap.removeChild(parentNode);
      }
    },
  };
};

export default {
  info,
  success,
  warn,
  error,
  loading,
};
